#ifndef UTIL_HPP
#define UTIL_HPP
#include <string>
using std::string;
#include <iostream>
#include <sstream>
#include <vector>
using std::vector;
#include <list>
using std::list;
#include <numeric>
#include <cmath>
using std::min;
using std::max;
using std::abs;
#include <cassert>
#include <stdarg.h>
#include <time.h>

/// A generic exception with a message string attached.
class MessageException
{
public:
	MessageException(string message);
	string toString();
protected:
	string message;
};

/// Given a string, mark each character according to whether it is escaped
/// (by a preceding backslash) and/or quoted. Quote characters are not
/// themselves quoted and backslashes are not themselves escaped (unless there
/// are two backslashes in a row).
/// TODO: Add support for backquotes
vector<char> tagString(string cmd);
enum QuoteTag {
	tagUnquoted     = 0x00,
	tagEscaped      = 0x01,
	tagSingleQuoted = 0x02,
	tagDoubleQuoted = 0x04,
};

/// Returns whether A is a prefix string of B (that is, exists C s.t. A+C=B. C
/// may be empty.)
bool isPrefix(string A, string B);

/// Fill a buffer with random data. (Used for creating test cases)
void randomFill(char *buf, int len);

bool stringIsInt(const string &str);

string stringListToString(const list<string> &strs);
list<string> stringToStringList(string str);

string timeToString(time_t time);

/// Given a string containing a sequence of whitespace-separated tokens, each
/// possibly enclosed in single or double quotes (which override whitespace),
/// separate the arguments into a vector of strings. Removes quotes and
/// evaluates backslash escape sequences. Also, a '#' not surrounded by quotes
/// is considered a comment marker and causes the rest of the string to be
/// ignored.
void separateArgs(vector<string> &args, const char *str, bool keepWhitespace=false, const char *separators=" \t\r\n");

/// Given a string, split it into separate strings wherever there is a newline.
/// The output goes in 'lines' and does not include any newline characters.
void separateLines(vector<string> &lines, const char *str);

/// Given a string possibly containing spaces and special characters, add
/// quotes if necessary to protect whitespace, and replace special chars with
/// escape sequences. Might include null characters, which become "\\x00".
string quoteProtectString(string str);

/// Given a string which is enclosed in single and double quotes, strip one
/// level of quotes and evaluate backslash escape sequences.
string unquoteString(const char *str);

/// Generate an escape sequence to represent a character. For common things
/// like \n or \a, generates that; otherwise, will use the form \x00. Note that
/// even printing chars like 'a' are converted into escape chars.
string getEscapeSequence(char ch);

/// Convert an escape sequence like '\n' or '\u1234' into a string
/// representation (usually one byte, but occasionally a multi-byte UTF-8
/// character). Returns the empty string if the sequence is truncated or
/// invalid, such as "\", "\xZ" or "\q". Advances the pointer which is passed
/// by reference to the first char which is not part of the escape sequence.
string parseEscapeSequence(const char *&start);

/// Return an integer chosen uniformly at random from [low,high]. Not suitable
/// for cryptographic use.
int randInt(int low, int high);

/// Open a file, load its contents, and return then. Returns NULL if the file
/// doesn't exist or couldn't be opened (with errno set as per fopen(3)). The
/// caller assumes ownership of the returned block of memory, which must be
/// free()ed.
/// The file is assumed to be textual and not to contain any null bytes. If it
/// does, they will be interpreted literally and mess up the string.
char *loadCompleteFile(const char *filename);

/// Fork, creating a pair of pipes between the parent and child. Returns the
/// child pid to the parent and 0 to the child, or -1 if there was an error (in
/// which case there is only one process and pipes[] is undefined). pipes[1] is the write end of a pipe
/// which goes to the other process, and pipes[0] is the read end of a pipe
/// which comes from it.
int connectedFork(int pipes[2]);

/// For functions that should be called on startup, before main().
struct StartupCaller
{
	StartupCaller(void(*func)()) {
		func();
	}
};

/// Get the file extension part of a filename, or "" if it has no extension
/// (such as if it's a directory).
string extractExtension(string filename);

/// Given a format string and an argument list, format it and return as a
/// std::string.
string retvprintf(const char *fmt, va_list args);

string retprintf(const char *fmt, ...);

#endif
